package fas

import (
	"Metro/dal/query"
	"Metro/protocol"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"github.com/panjf2000/gnet/v2"
	"jialiking.com/gaogang/common/utils"
	"strconv"
	"strings"
	"sync"
	"time"
	"unicode/utf16"
)

var SIGNALS = []Signal{
	{
		key:      "fas_control",
		active:   []string{"开"},
		inactive: []string{"关"},
	},
	{
		key:      "fas_fire",
		active:   []string{"火灾报警", "确认火灾报警"},
		inactive: []string{"火警已清除"},
	},
	{
		key:      "fas_fault",
		active:   []string{"非消防故障", "确认非火警故障"},
		inactive: []string{"非火警故障已清除"},
	},
	{
		key:      "fas_fire_fault",
		active:   []string{"消防故障", "确认消防故障"},
		inactive: []string{"火警故障已清除"},
	},
	{
		key:      "fas_isolation",
		active:   []string{"非消防设备屏蔽", "确认非消防设备已被屏蔽"},
		inactive: []string{"对非消防设备的屏蔽已清除"},
	},
	{
		key:      "fas_monitor",
		active:   []string{"监控站监控信号", "确认巡更监控信号"},
		inactive: []string{"监视信号（巡更）已解除"},
	},

	//{
	//	key:      "gas_control",
	//	active:   []string{"开"},
	//	inactive: []string{"关"},
	//},
	//{
	//	key:      "gas_fire",
	//	active:   []string{"火灾报警", "确认火灾报警"},
	//	inactive: []string{"火警已清除"},
	//},
	//{
	//	key:      "gas_fault",
	//	active:   []string{"非消防故障", "确认非火警故障"},
	//	inactive: []string{"非火警故障已清除"},
	//},
	//{
	//	key:      "gas_fire_fault",
	//	active:   []string{"消防故障", "确认消防故障"},
	//	inactive: []string{"火警故障已清除"},
	//},
	//{
	//	key:      "gas_isolation",
	//	active:   []string{"非消防设备屏蔽", "确认非消防设备已被屏蔽"},
	//	inactive: []string{"对非消防设备的屏蔽已清除"},
	//},
	//{
	//	key:      "gas_monitor",
	//	active:   []string{"监控站监控信号", "确认巡更监控信号"},
	//	inactive: []string{"监视信号（巡更）已解除"},
	//},
}

var Server = fasServer{}

type fasServer struct {
	gnet.BuiltinEventEngine
	Eng           *gnet.Engine
	MacAdapterMap *sync.Map
}

type ConnectionProperty struct {
	lock                *sync.Mutex
	con                 gnet.Conn
	currentGroupCommand *string
	groupLock           *sync.Mutex
}

type Signal struct {
	key      string
	active   []string
	inactive []string
}

func init() {
	Server.MacAdapterMap = &sync.Map{}
}

func (server fasServer) OnBoot(eng gnet.Engine) gnet.Action {
	server.Eng = &eng
	return gnet.None
}

func (server fasServer) OnOpen(c gnet.Conn) (out []byte, action gnet.Action) {
	utils.GlobalLog("fas connection: %s", c.RemoteAddr().String())
	return
}

func (server fasServer) OnTraffic(c gnet.Conn) gnet.Action {
	for {
		if c.Context() == nil {
			mac, _ := c.Peek(9)
			if len(mac) < 9 {
				return gnet.None
			}
			c.SetContext(string(mac))
			_, _ = c.Discard(9)
		}

		mac, _ := c.Peek(9)
		if len(mac) < 9 {
			return gnet.None
		}
		if string(mac) == c.Context().(string) {
			utils.GlobalLog("heartbeat: %s", string(mac))
			_, _ = c.Discard(9)
			protocol.UpdateHostOnline(string(mac))
			return gnet.None
		}

		data, _ := c.Peek(c.InboundBuffered())
		if len(data) != 0 {
			position := strings.Index(string(data), string([]byte{0x00, 0x0d, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x0a}))
			if position != -1 {
				validData := data[:position]
				var uint16Data []uint16
				for i := 0; i < len(validData); i += 2 {
					uint16Data = append(uint16Data, binary.BigEndian.Uint16(data[i:i+2]))
				}
				str := string(utf16.Decode(uint16Data))
				process(c.Context().(string), str)
				_, _ = c.Discard(position + 8)
			} else {
				if len(data) > 1024*1024 {
					utils.GlobalLog("cache data is too larger, more than 1MB, close connection")
					return gnet.Close
				}
				return gnet.None
			}
		} else {
			return gnet.None
		}
	}
}

func process(mac string, str string) {
	utils.InfoLog("mac: %s, data: %s", mac, str)
	host, _ := query.Host.Where(query.Host.Gateway.Eq(mac)).Take()
	if host == nil {
		utils.ErrorLog("fas host not found")
		return
	}

	str = strings.ReplaceAll(str, "\n", "")
	str = strings.ReplaceAll(str, "\t", "")
	str = strings.ReplaceAll(str, "\r", "")

	items := strings.Split(str, "     ")
	var validItems []string
	for _, item := range items {
		if item != "" {
			validItems = append(validItems, strings.TrimSpace(item))
		}
	}
	//if len(validItems) != 5 && len(validItems) != 7 {
	//	utils.ErrorLog("invalid data")
	//	return
	//}
	sig := validItems[0]
	t := validItems[len(validItems)-2]
	addr := validItems[len(validItems)-1]
	utils.InfoLog("sig: %s, time: %s, addr: %s", sig, t, addr)
	device, _ := query.Device.Preload(query.Device.EnumItem).Where(query.Device.HostID.Eq(host.ID), query.Device.Addr.Eq(addr)).Take()
	if device == nil {
		utils.ErrorLog("device not found")
		return
	}

	result := make(map[string]float64)
	if device.LastReportData != nil {
		err := json.Unmarshal([]byte(*device.LastReportData), &result)
		if err != nil {
			utils.ErrorLog("json unmarshal error: %v", err)
			result = make(map[string]float64)
		}
	}
	for _, signal := range SIGNALS {
		if utils.ContainStr(signal.active, sig) {
			result[signal.key] = 1
		} else if utils.ContainStr(signal.inactive, sig) {
			result[signal.key] = 0
		} else {
			continue
		}
		marshal, err := json.Marshal(result)
		if err != nil {
			utils.ErrorLog("json marshal error: %v", err)
			return
		}
		_, err = query.Device.Where(query.Device.ID.Eq(device.ID)).Updates(map[string]any{
			"last_report_data": string(marshal),
			"last_report_date": time.Now(),
		})
		if err != nil {
			utils.ErrorLog("update device error: %v", err)
			return
		}
		thresholds, _ := query.Threshold.Where(query.Threshold.DefinitionID.Eq(*device.DefinitionID), query.Threshold.Field.Eq(signal.key)).Find()
		if thresholds != nil {
			for _, threshold := range thresholds {
				floatValue, err := strconv.ParseFloat(threshold.Value, 64)
				if err != nil {
					utils.ErrorLog("Error converting string to float:", err)
					continue
				}
				if threshold.Comparison == "=" && floatValue == result[signal.key] {
					//触发报警
					protocol.TriggerEvent(*device, threshold, fmt.Sprintf("%f", result[signal.key]))
				}
				if threshold.Comparison == "=" && floatValue != result[signal.key] {
					protocol.ClearEvent(*device, threshold, fmt.Sprintf("%f", result[signal.key]))
				}
			}
		}
		break
	}
}

func (server fasServer) OnClose(c gnet.Conn, e error) (action gnet.Action) {
	utils.GlobalLog("device disconnection: %s, %s", c.RemoteAddr().String(), e.Error())
	return
}

func (server fasServer) OnTick() (delay time.Duration, action gnet.Action) {
	return 1 * time.Minute, action
}

func Test() {
	//process("zqwl-0003", "火警已清除                          电磁阀      探测器 L01D001                             \n区域                   Z001  烟感（光电）       01:04:41P SUN JUN 30, 2024     L01D001")
}
